<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <title>libQGLViewer standardCamera example</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <link href="../qglviewer.css" rel="stylesheet" type="text/css" />
  <link rel="shortcut icon" href="../images/qglviewer.ico" type="image/x-icon" />
  <link rel="icon" href="../images/qglviewer.icon.png" type="image/png" />
<script type="text/javascript">

  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-23223012-2']);
  _gaq.push(['_trackPageview']);

  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();

</script>
</head>
<body>

<div class="banner">
 <a class="qindex" href="../index.html">Home</a>
 <a class="qindex" href="../download.html">Download</a>
 <a class="qindex highlight" href="index.html">Gallery</a>
 <a class="qindex" href="../refManual/hierarchy.html">Documentation</a>
 <a class="qindex" href="../developer.html">Developer</a>
</div>

<h1>The standardCamera example</h1>

<center>
  <img src="../images/standardCamera.jpg" width="330" height="228" alt="standardCamera"/>
</center>

<p>
 A 'standard' Camera with fixed near and far planes.
</p>
<p>
 A new <code>StandardCamera</code> class is derived from <code>Camera</code>.
 Its near and far planes distances are set to fixed values (instead of being fit to
 scene dimensions as is done in the <code>QGLViewer::Camera</code>).
</p>
<p>
 The orthographic frustum dimensions are fixed instead of depending on the distance
 to the <code>pivotPoint()</code>. Since this may be needed for some applications,
 you may want to use this <code>standardCamera</code> class in your code.
</p>
<h2>standardCamera.h</h2>
<pre>
#include &lt;QGLViewer/camera.h&gt;

class StandardCamera : public qglviewer::Camera {
public:
  StandardCamera();

  virtual qreal zNear() const;
  virtual qreal zFar() const;

  void toggleMode() { standard = !standard; }
  bool isStandard() { return standard; }

  void changeOrthoFrustumSize(int delta);
  virtual void getOrthoWidthHeight(GLdouble &amp;halfWidth,
                                   GLdouble &amp;halfHeight) const;

private:
  bool standard;
  float orthoSize;
};
</pre>


<h2>standardCamera.cpp</h2>
<pre>
#include "standardCamera.h"

#include &lt;QWheelEvent&gt;

using namespace qglviewer;

StandardCamera::StandardCamera() {
  standard = true;
  orthoSize = 1.0;
}

qreal StandardCamera::zNear() const {
  if (standard)
    return 0.001;
  else
    return Camera::zNear();
}

qreal StandardCamera::zFar() const {
  if (standard)
    return 1000.0;
  else
    return Camera::zFar();
}

void StandardCamera::changeOrthoFrustumSize(int delta) {
  if (delta &gt; 0)
    orthoSize *= 1.1;
  else
    orthoSize /= 1.1;
}

void StandardCamera::getOrthoWidthHeight(GLdouble &amp;halfWidth,
                                         GLdouble &amp;halfHeight) const {
  if (standard) {
    halfHeight = orthoSize;
    halfWidth = aspectRatio() * orthoSize;
  } else
    Camera::getOrthoWidthHeight(halfWidth, halfHeight);
}
</pre>


<h2>cameraViewer.h</h2>
<pre>
#include &lt;QGLViewer/qglviewer.h&gt;

class CameraViewer : public QGLViewer {
public:
  CameraViewer(qglviewer::Camera *camera);

protected:
  virtual void draw();
  virtual void init();

private:
  qglviewer::Camera *c;
};
</pre>


<h2>viewer.h</h2>
<pre>
#include &lt;QGLViewer/qglviewer.h&gt;

class StandardCamera;

class Viewer : public QGLViewer {
  Q_OBJECT

public:
  Viewer(StandardCamera *camera);

public:
Q_SIGNALS:
  void cameraChanged();

protected:
  virtual void draw();
  virtual void init();
  virtual QString helpString() const;
  virtual void keyPressEvent(QKeyEvent *e);
  virtual void wheelEvent(QWheelEvent *e);

private:
  void showMessage();
};
</pre>


<h2>cameraViewer.cpp</h2>
<pre>
#include "cameraViewer.h"

using namespace qglviewer;

CameraViewer::CameraViewer(Camera *camera) : c(camera){};

void CameraViewer::draw() {
  // Exactly the same draw than for 'Viewer'. The two viewers could also share a
  // 'Scene' instance.
  const float nbSteps = 200.0;

  glBegin(GL_QUAD_STRIP);
  for (int i = 0; i &lt; nbSteps; ++i) {
    const float ratio = i / nbSteps;
    const float angle = 21.0 * ratio;
    const float c = cos(angle);
    const float s = sin(angle);
    const float r1 = 1.0 - 0.8f * ratio;
    const float r2 = 0.8f - 0.8f * ratio;
    const float alt = ratio - 0.5f;
    const float nor = 0.5f;
    const float up = sqrt(1.0 - nor * nor);
    glColor3f(1.0 - ratio, 0.2f, ratio);
    glNormal3f(nor * c, up, nor * s);
    glVertex3f(r1 * c, alt, r1 * s);
    glVertex3f(r2 * c, alt + 0.05f, r2 * s);
  }
  glEnd();

  // Draws the other viewer's camera
  glDisable(GL_LIGHTING);
  glLineWidth(4.0);
  glColor4f(1.0, 1.0, 1.0, 0.5);
  c-&gt;draw();
  glEnable(GL_LIGHTING);
}

void CameraViewer::init() {
  // Places the cameraViewer's camera far away in order to see the (other
  // viewer) camera.
  if (!restoreStateFromFile()) {
    // Make near and far planes much further from scene in order not to clip c's
    // display.
    camera()-&gt;setZClippingCoefficient(50.0);
    camera()-&gt;setViewDirection(qglviewer::Vec(0.0, -1.0, 0.0));
    showEntireScene();
  }

  // Enable semi-transparent culling planes
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
</pre>


<h2>main.cpp</h2>
<pre>
#include "cameraViewer.h"
#include "standardCamera.h"
#include "viewer.h"

#include &lt;QApplication&gt;
#include &lt;QGLViewer/manipulatedCameraFrame.h&gt;

int main(int argc, char **argv) {
  QApplication application(argc, argv);

  // Instantiate the two viewers.
  StandardCamera *sc = new StandardCamera();
  Viewer viewer(sc);
  CameraViewer cviewer(sc);

  // Make sure every v camera movement updates the camera viewer
  QObject::connect(viewer.camera()-&gt;frame(), SIGNAL(manipulated()), &amp;cviewer,
                   SLOT(updateGL()));
  QObject::connect(viewer.camera()-&gt;frame(), SIGNAL(spun()), &amp;cviewer,
                   SLOT(updateGL()));
  // Also update on camera change (type or mode)
  QObject::connect(&amp;viewer, SIGNAL(cameraChanged()), &amp;cviewer,
                   SLOT(updateGL()));

  viewer.setWindowTitle("standardCamera");
  cviewer.setWindowTitle("Camera viewer");

  cviewer.show();
  viewer.show();

  return application.exec();
}
</pre>


<h2>viewer.cpp</h2>
<pre>
#include "viewer.h"
#include "standardCamera.h"

#include &lt;QKeyEvent&gt;

#if QT_VERSION &gt; QT_VERSION_CHECK(6, 0, 0)
#define MidButton MiddleButton
#endif

using namespace std;
using namespace qglviewer;

Viewer::Viewer(StandardCamera *nfc) {
  // Change the camera.
  Camera *c = camera();
  setCamera(nfc);
  delete c;
}

// Draws a spiral
void Viewer::draw() {
  const float nbSteps = 200.0;

  glBegin(GL_QUAD_STRIP);
  for (int i = 0; i &lt; nbSteps; ++i) {
    const float ratio = i / nbSteps;
    const float angle = 21.0 * ratio;
    const float c = cos(angle);
    const float s = sin(angle);
    const float r1 = 1.0 - 0.8f * ratio;
    const float r2 = 0.8f - 0.8f * ratio;
    const float alt = ratio - 0.5f;
    const float nor = 0.5f;
    const float up = sqrt(1.0 - nor * nor);
    glColor3f(1.0 - ratio, 0.2f, ratio);
    glNormal3f(nor * c, up, nor * s);
    glVertex3f(r1 * c, alt, r1 * s);
    glVertex3f(r2 * c, alt + 0.05f, r2 * s);
  }
  glEnd();
}

void Viewer::init() {
  // Restore previous viewer state.
  if (!restoreStateFromFile())
    showEntireScene();

  setKeyDescription(Qt::Key_T,
                    "Toggles camera type (perspective or orthographic)");
  setKeyDescription(Qt::Key_M, "Toggles camera mode (standard or QGLViewer)");

  setMouseBindingDescription(
      Qt::ShiftModifier, Qt::MidButton,
      "Change frustum size (for standard camera in orthographic mode)");

  // Display help window.
  help();
}

void Viewer::showMessage() {
  QString std = ((StandardCamera *)camera())-&gt;isStandard() ? "Standard camera"
                                                           : "QGLViewer camera";
  QString type =
      camera()-&gt;type() == Camera::PERSPECTIVE ? "Perspective" : "Orthographic";
  displayMessage(std + " - " + type);
  Q_EMIT cameraChanged();
}

void Viewer::keyPressEvent(QKeyEvent *e) {
  if (e-&gt;key() == Qt::Key_M) {
    // 'M' changes mode : standard or QGLViewer camera
    ((StandardCamera *)camera())-&gt;toggleMode();
    showMessage();
  } else if (e-&gt;key() == Qt::Key_T) {
    // 'T' changes the projection type : perspective or orthogonal
    if (camera()-&gt;type() == Camera::ORTHOGRAPHIC)
      camera()-&gt;setType(Camera::PERSPECTIVE);
    else
      camera()-&gt;setType(Camera::ORTHOGRAPHIC);
    showMessage();
  } else
    QGLViewer::keyPressEvent(e);
}

void Viewer::wheelEvent(QWheelEvent *e) {
  if ((camera()-&gt;type() == Camera::ORTHOGRAPHIC) &amp;&amp;
      (((StandardCamera *)camera())-&gt;isStandard()) &amp;&amp;
      (e-&gt;modifiers() &amp; Qt::ShiftModifier)) {
#if QT_VERSION &lt; QT_VERSION_CHECK(6, 0, 0)
    ((StandardCamera *)camera())-&gt;changeOrthoFrustumSize(e-&gt;delta());
#else
    ((StandardCamera *)camera())-&gt;changeOrthoFrustumSize(e-&gt;angleDelta().y());
#endif
    Q_EMIT cameraChanged();
    update();
  } else
    QGLViewer::wheelEvent(e);
}

QString Viewer::helpString() const {
  QString text("&lt;h2&gt;S t a n d a r d C a m e r a&lt;/h2&gt;");
  text += "An overloaded &lt;code&gt;Camera&lt;/code&gt; class is used, that reproduces "
          "the 'standard' OpenGL settings.&lt;br&gt;&lt;br&gt;";

  text += "With this camera, the near and (resp. far) plane distance is set to "
          "a very small (resp. very large) value. ";
  text += "With the orthographic camera type, the frustum dimensions are "
          "fixed. Use &lt;code&gt;Shift&lt;/code&gt; and the mouse wheel to change "
          "them.&lt;br&gt;&lt;br&gt;";

  text += "On the other hand, the QGLViewer camera fits the near and far "
          "distances to the scene radius. ";
  text += "Fine tuning is available using &lt;code&gt;zClippingCoefficient()&lt;/code&gt; "
          "and &lt;code&gt;zNearCoefficient()&lt;/code&gt;. ";
  text += "However, visual results do not seem to be impacted by this zBuffer "
          "fitted range.&lt;br&gt;&lt;br&gt;";
  text += "The QGLViewer camera also adapts the orthographic frustum "
          "dimensions to the distance to the &lt;code&gt;pivotPoint()&lt;/code&gt; to "
          "mimic a perspective camera. ";
  text += "Since this behavior may not be needed, this example shows how to "
          "override it.&lt;br&gt;&lt;br&gt;";

  text += "The second viewer displays the first one's camera to show its "
          "configuration.&lt;br&gt;&lt;br&gt;";

  text += "Use &lt;b&gt;M&lt;/b&gt; to switch between 'standard' and QGLViewer camera "
          "behavior.&lt;br&gt;";
  text += "Use &lt;b&gt;T&lt;/b&gt; to switch between perspective and orthographic camera "
          "type.&lt;br&gt;&lt;br&gt;";

  text += "Use &lt;b&gt;Shift+wheel&lt;/b&gt; to change standard camera orthographic size.";

  return text;
}
</pre>



<p>
  Back to the <a href="index.html">examples main page</a>.
</p>

</body>
</html>
